using System;
using System.Text.RegularExpressions;


namespace SMS.ProcessUtils
{

	public enum PhoneNumberTypes 
	{
		International = -1,
		Automatic = 0,
		USA = 1,
		VN = 2
	}

	public enum ZipCodeTypes
	{
		Automatic = 0,
		USA = 1
	}

	public enum DateFormat
	{
		Automatic = 0,
		mm_dd_yy = 1,
		mm_dd_yyyy = 2
	}

	public enum CaseOptions
	{
		Automatic = 0,
		CaseSensitive = 1,
		CaseInsensitive = 2
	}

	public enum NumberFormat
	{
		Automatic = 0,
		NoCommas = 1,
		HasCommas = 2,
		Scientific = 3,
		NoCommasWithDecimal = 4,
		HasCommasWithDecimal = 5
	}

	public enum NationalIDType
	{
		Automatic = 0,
		USA_SSN = 1,
		USA_EIN = 2
	}


	[Flags()]
	public enum AlphaNumMatchOptions
	{
		Automatic = 0,
		AllowSpecialCharacters = 1,
		AllowSpaces = (2 ^ 1),
		UseUnderscore = (2 ^ 2),
		AlphaOnly = (2 ^ 3),
		NumericOnly = (2 ^ 4),
		AllowUnderscore = (2 ^ 5)
	}
   
	[Flags()]
	public enum NumberFormatOptions
	{
		Automatic = 0,
		AcceptCommas = 1,
		AcceptDecimal = (2 ^ 1),
		AcceptNegative = (2 ^ 2),
		RejectCommas = (2 ^ 3),
		RejectDecimal = (2 ^ 4),
		RejectNegative = (2 ^ 5),
		Scientic = (2 ^ 6)
	}

	public class Validators 
	{
		public static bool IsExpectedLength(ref string text, int length)
		{
			if (text == null) 
				return false;

			if ((text.Length <= length) && length > 0) 
				return true;

			return false;
		}


		public static bool IsExactLength(ref string text, int length) 
		{
			if (text == null) 
				return false;

			if (text.Length == length) 
				return true;

			return false;
		}

		public static bool IsMinimumLength(ref string text, int length)
		{
			if (text == null) 
				return false;

			if (length < 0) 
				return false;
         
			if (text.Length >= length) 
				return true;
         
			return false;
		}
      

		// Validate if the given string is a phone number
		// : ###-###-####
		// : ### ###-####
		// : (###) ###-####
		// : (###)-###-####
		// : 0904883482
		// : 84904883482

		public static bool IsPhoneNumber(string value, PhoneNumberTypes type)
		{
			switch (type) 
			{
				case PhoneNumberTypes.USA:
            
					if (IsExpectedLength(ref value, 14)) 
					{
						return Regex.IsMatch(value, @"^(\(\d{3}\)|\d{3})(\s?|-)\d{3}-\d{4}$");
					}
					break;

				case PhoneNumberTypes.VN:
   
					if (IsExpectedLength(ref value, 11) && value.Length>2) 
					{
						if(value.Substring(0,2)=="09")
							return Regex.IsMatch(value, @"^\d{10}$");
					}
					break;
               
				case PhoneNumberTypes.International:
   
					if (IsExpectedLength(ref value, 11) && value.Length>2) 
					{
						if(value.Substring(0,2)=="84")
							return Regex.IsMatch(value, @"^\d{11}$");
					}
					break;
            
				case PhoneNumberTypes.Automatic:
            
					if (IsPhoneNumber(value, PhoneNumberTypes.USA)) 
					{
						return true;
					}
					else if (IsPhoneNumber(value, PhoneNumberTypes.International)) 
					{
						return true;
					}
					break;
			}

			return false;
		}

		public static string FormatMobileNo(string strMobileNo)
		{
			string strCountryCode = "84";
			strMobileNo = strCountryCode + strMobileNo.Substring(1);

			return strMobileNo;
		}

		// Validate if teh given string is a postal code
		public static bool IsPostalCode(string value, ZipCodeTypes type) 
		{
			return IsZipCode(value, type);
		}
      
      
		// Validate if the given string is a Zip Code
		// USA:
		// : #####
		// : #####-####
		public static bool IsZipCode(string value, ZipCodeTypes type)
		{
			switch (type) 
			{
				case ZipCodeTypes.USA:
					return Regex.IsMatch(value, @"^\d{5}(-\d{4})?$");
            
				case ZipCodeTypes.Automatic:
					if (IsZipCode(value, ZipCodeTypes.USA)) 
					{
						return true;
					}
					break;
			}
			return false;
		}


		// Validate if the given string is an email address
		// : someone@somewhere.com / .net / .mil / .gov / .org
		// : someone@somewhere.co.uk
		// : someone@somewhere.info
		public static bool IsEmailAddress(string value)
		{
			if (value == null) 
				return false;

			return Regex.IsMatch(value, @"^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
		}


		// Validate if the given string is an IP address
		// : ###.###.###.### (### cannot be greater thatn 255)
		public static bool IsIPAddress(string value)
		{ 
			if (IsExpectedLength(ref value, 15)) 
				return Regex.IsMatch(value, @"^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$");

			return false;
		}


		// Validate if the given string is a Date
		// : ##/##/##
		// : ##/##/####
		// : ##-##-##
		// : ##-##-####
		// : ##.##.##
		// : ##.##.####
		public static bool IsDate(string value, DateFormat type) 
		{
			if (value == null) 
				return false;

			switch (type)
			{
				case DateFormat.mm_dd_yy:
					return Regex.IsMatch(value, @"^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$");

				case DateFormat.mm_dd_yyyy:
					return Regex.IsMatch(value, @"^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$");


				case DateFormat.Automatic:
					if (IsDate(value, DateFormat.mm_dd_yy)) 
						return true;
					
                    else if (IsDate(value, DateFormat.mm_dd_yyyy)) 
						return true;
					
                    break;
			}

			return false;
		}


		// Validate if the given string is a State abbr.
		// : @@
		public static bool IsStateUSA(string value, CaseOptions options)
		{
			if (IsExactLength(ref value, 2)) 
			{      
				switch (options) 
				{
					case CaseOptions.CaseSensitive:
						return Regex.IsMatch(value, @"^(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NB|NC|ND|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)$");

					case CaseOptions.CaseInsensitive:
						return Regex.IsMatch(value, @"^(?i:AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NB|NC|ND|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)$");
            
					case CaseOptions.Automatic:
						return IsStateUSA(value, CaseOptions.CaseInsensitive);
				}
			}

			return false;
		}

		// Validate if the value is a specific type of ID pertaining to a particular nationality.
		public static bool IsNationalID(string value, NationalIDType type)
		{   
			switch (type)
			{
				case NationalIDType.USA_SSN:
					if (IsExactLength(ref value, 9) || IsExactLength(ref value, 11)) 
						return Regex.IsMatch(value, @"^\d{3}\-\d{2}\-\d{4}$");
					
                    break;
         
				case NationalIDType.USA_EIN:
					return Regex.IsMatch(value, @"^[0-9]{2}-[0-9]{7}$");
         
         
				case NationalIDType.Automatic:
					if (IsNationalID(value, NationalIDType.USA_SSN)) 
						return true;
					
                    else if (IsNationalID(value, NationalIDType.USA_EIN)) 
						return true;
					
                    break;
			}

			return false; 
		}

		// Validate if the given string is a SSN
		// : ###-##-####
		public static bool IsSSN(string value) 
		{
			return IsNationalID(value, NationalIDType.USA_SSN);
		}

		// Validate if the given string is a time
		// : ##:##
		public static bool IsTime(string value)
		{
			if (value == null) 
				return false;

			return Regex.IsMatch(value, @"^([1-9]|1[0-2]):[0-5]\d$");
		}

		// Validate if the string has any potential malicious scripting code, assuming this is a querystring.
		public static bool IsSafeQuerystring(string value) 
		{
			if (value == null || value == "") 
				return true;

			return !Regex.IsMatch(value, @"(?i:<script>|</script>|;|\{|\}|')");
		}

		// Validate if the string is number
		// : ########
		// : ###,###
		// : #####.###
		// : ###,###.##
		// : +##.##
		// : -##.##
		// : +###.e+##
		// : etc.
		public static bool IsNumber(string value, NumberFormat type)
		{
			if (value == null) 
				return false;

			switch (type) 
			{
				case NumberFormat.NoCommas:
					return Regex.IsMatch(value, @"^(\d+)$|^\-(\d+)$|^\((\d+)\)$");
 
				case NumberFormat.HasCommas:
					return Regex.IsMatch(value, @"^(\d{1,3}(,\d{3})*)$|^\-(\d{1,3}(,\d{3})*)$|^\((\d{1,3}(,\d{3})*)\)$");
 
				case NumberFormat.Scientific:
					return Regex.IsMatch(value, @"^[-+]{1}?\d*(\.\d+|\d*)(e[+-]?\d+)?$");
    
				case NumberFormat.NoCommasWithDecimal:
					return Regex.IsMatch(value, @"^\d+(\.\d+)$|^\-\d+(\.\d+)$|^\(\d+(\.\d+)\)$");
    
				case NumberFormat.HasCommasWithDecimal:
					return  Regex.IsMatch(value, @"^\d{1,3}(,\d{3})*(\.\d+)$|^\-\d{1,3}(,\d{3})*(\.\d+)$|^\(\d{1,3}(,\d{3})*(\.\d+)\)$");

				case NumberFormat.Automatic:
					if (IsNumber(value, NumberFormat.NoCommas)) 
						return true;
					
					else if (IsNumber(value, NumberFormat.HasCommas)) 
						return true;
					
					else if (IsNumber(value, NumberFormat.Scientific)) 
						return true;
					
					else if (IsNumber(value, NumberFormat.NoCommasWithDecimal)) 
						return true;
					
					else if (IsNumber(value, NumberFormat.HasCommasWithDecimal)) 
						return true;
					
					break;
			}

			return false;
		}
      
		// Validate if the given string is currency
		// : $###,###.##
		public static bool IsCurrency(string value, int precision)
		{
			if (value == null) 
				return false;

			if (precision <= 0) 
				return false;

			return Regex.IsMatch(value, @"^\$\d{1,3}(,\d{3})*\.\d{" + precision.ToString() + @"}|^\-\$\d{1,3}(,\d{3})*\.\d{" + precision.ToString() + @"}|^\(\$\d{1,3}(,\d{3})*\.\d{" + precision.ToString() + @"}\)");
		}

		// Validate if the string is alphanumeric (spaces not accepted, instead, use _)
		public static bool IsAlphaNumeric(string value)
		{
			if (value == null) 
				return false;

			return Regex.IsMatch(value, @"^([a-zA-Z\d_]+)$");
		}
        
		// Validate if the string is alphanumeric (spaces not accepted, instead use _) for
		// querystring. % symbol must be accepted, as well as a few others. Also, as an
		// added bonus, it will return false if any of the JavaScript/JScript function 
		// characters are found, { } ; <></> as in <script> </script>.  But to check
		// for malicious code specifically, use IsSafeQuerystring instead.
		public static bool IsAlphaNumericQS(string value)
		{
			if (value == null) 
				return false;
			
            return Regex.IsMatch(value, @"^([a-zA-Z\d_\-%#@!:^~\$+]+)$");
		}

		// Validate if the string is alpha characters only
		public static bool IsAlpha(string value)
		{
			if (value == null) 
				return false;
			
			return Regex.IsMatch(value, @"^([a-zA-Z_\s]+)$");
		}
      
		// Validate if the supplied string matches a certain criteria, for example, if a UserName meets conditions, or a Password meets conditions...
		public static bool IsCriteriaAcceptable(string value, int minCaps, int minSpecialChars, int minNumbers, int minLength, int maxLength) 
		{
			// First check and ensure the minimum length is met
			if (!IsMinimumLength(ref value, minLength)) 
				return false;
         
			// Make sure the text isn//t more than the maximum length specified
			if (value.Length > maxLength) 
				return false;

			// Check is see if there are minimum number of caps supplied
			if (!Regex.IsMatch(value, @"([A-Z].*){" + minCaps.ToString() + "}")) 
				return false;

			// Check to see if there are minimum number of numbers supplied
			if (!Regex.IsMatch(value, @"([0-9].*){" + minNumbers.ToString() + "}")) 
				return false;
         
			// Check to see if there are minimum number of special characters supplied
			if (!Regex.IsMatch(value, @"([_~!@#\$%^&\-_+=;:\.,].*){" + minSpecialChars.ToString() + "}")) 
				return false;
			
			return true;
		}
      
		// Validate if the value is a variant of boolean. Case insensitive.
		public static bool IsBoolean(string value)
		{
			if (value == null) 
				return false;
			
            return Regex.IsMatch(value, @"^(1|0)$|^(?i:TRUE|FALSE)$|^(?i:YES|NO)$|^(?i:ON|OFF)$");
		}
      
		// Validate gender. Case insensitive.
		public static bool IsGender(string value)
		{
			if (value == null) 
				return false;
			
			return Regex.IsMatch(value, @"^(?i:MALE|FEMALE)$|^(?i:M|F)$|^(1|0)$");
		}
      
		// Validate if the value is USA Employer TaxID Number.
		public static bool IsEIN(string value)
		{
			return IsNationalID(value, NationalIDType.USA_EIN);
		}
	}
}